从面向过程到面向对象

# 从面向过程到面向对象

原则: 先写出普通的写法,然后改成面向对象写法

  1. 普通方法变型
    • 尽量不要出现函数嵌套函数
    • 可以有全局变量
    • 把onload中不是赋值的语句放到单独函数中
  2. 改成面向对象
    • 全局变量就是属性
    • 函数就是方法
    • onload中创建对象
    • 改this指向问题 [TOC]

# 一、传统的过程式编写选项卡

//普通写法
window.onload = function(){
    var oParent = document.getElementById('div1');
    var aInput = oParent.getElementsByTagName('input');
    var aDiv = oParent.getElementsByTagName('div');

    for(var i=0;i<aInput.length;i++){
        aInput[i].index = i;
        aInput[i].onclick = function(){
            for(var i=0;i<aInput.length;i++){
                aInput[i].className = '';
                aDiv[i].style.display = 'none';
            }
            this.className = 'active';
            aDiv[this.index].style.display = 'block';
        };
    }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17

# 1.1 先变型

  1. 尽量不要出现函数嵌套函数
  2. 可以有全局变量
  3. onload中不是赋值的语句放到单独函数中
var oParent = null;
var aInput = null;
var aDiv = null;

window.onload = function(){
    
    oParent = document.getElementById('div1');
    aInput = oParent.getElementsByTagName('input');
    aDiv = oParent.getElementsByTagName('div');

    init();
    
};

function init(){
    for(var i=0;i<aInput.length;i++){
        aInput[i].index = i;
        aInput[i].onclick = change;
    }
}

function change(){
    for(var i=0;i<aInput.length;i++){
        aInput[i].className = '';
        aDiv[i].style.display = 'none';
    }
    this.className = 'active';
    aDiv[this.index].style.display = 'block';
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29

# 1.2 改成面向对象

  1. 全局变量就是属性
  2. 函数就是方法
  3. onload中创建对象
  4. this指向问题 : 事件或者是定时器,尽量让面向对象中的this指向对象
oDiv.onclick = function(){
    this : oDiv
};


oDiv.onclick = show;
function show(){
    this : oDiv
}


oDiv.onclick = function(){
    show();
};
function show(){
    this : window
}

oDiv.onclick = this.change;
//this.change函数是事件直接执行的函数
//this指向的是oDiv
//这里不加括号是事件触发的时候自然会调用,这里不需要(也不能加,加了就立即调用了)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

# 二、面向对象的选项卡

window.onload = function(){
    
    var t1 = new Tab();//注意第一个字母是大写
    t1.init();
    
};

function Tab(){
    this.oParent = document.getElementById('div1');
    this.aInput = this.oParent.getElementsByTagName('input');
    this.aDiv = this.oParent.getElementsByTagName('div');
}

Tab.prototype.init = function(){
    var This = this;
    for(var i=0;i<this.aInput.length;i++){
        this.aInput[i].index = i;
        this.aInput[i].onclick = function(){
            This.change(this);//这里的this是按钮,This是对象
        };
    }
};
//var _this = this;
////这个匿名函数是事件直接执行的事件函数
//oDiv.onclick = function() {
////现在这个change函数是被_this调用的,而不是oDiv的事件,所以change函数内部this指向_this,加括号是调用
//    _this.change();
//}
Tab.prototype.change = function(obj){
    for(var i=0;i<this.aInput.length;i++){
        this.aInput[i].className = '';
        this.aDiv[i].style.display = 'none';
    }
    obj.className = 'active';
    this.aDiv[obj.index].style.display = 'block';
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

# 三、控制多个选项卡自动播放

window.onload = function(){
	
	var t1 = new Tab('div1');
	t1.init();
	t1.autoPlay();
	
	var t2 = new Tab('div2');
	t2.init();
	t2.autoPlay();
	
};

//在前面的基础上添加
Tab.prototype.autoPlay = function(){
	
	var This = this;
	
	setInterval(function(){
		
		if(This.iNow == This.aInput.length-1){
			This.iNow = 0;
		}
		else{
			This.iNow++;
		}
		
		for(var i=0;i<This.aInput.length;i++){
			This.aInput[i].className = '';
			This.aDiv[i].style.display = 'none';
		}
		This.aInput[This.iNow].className = 'active';
		This.aDiv[This.iNow].style.display = 'block';
		
		
	},2000);
	
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37

学会了吗

让我们再来巩固一下

# 四、用面向对象编写拖拽

window.onload = function(){
    var oDiv = document.getElementById('div1');
    
    var disX = 0;
    var disY = 0;
    
    oDiv.onmousedown = function(ev){
        var ev = ev || window.event;
        disX = ev.clientX - oDiv.offsetLeft;
        disY = ev.clientY - oDiv.offsetTop;
        
        document.onmousemove = function(ev){
            var ev = ev || window.event;
            oDiv.style.left = ev.clientX - disX + 'px';
            oDiv.style.top = ev.clientY - disY + 'px';
        };
        
        document.onmouseup = function(){
            document.onmousemove = null;
            document.onmouseup = null;
        };
        return false;
    };
    
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25

# 4.1 变个型

var oDiv = null;
var disX = 0;
var disY = 0;

window.onload = function(){
    oDiv = document.getElementById('div1');
    init();
};

function init(){
    oDiv.onmousedown = fnDown;
}

function fnDown(ev){
    var ev = ev || window.event;
    disX = ev.clientX - oDiv.offsetLeft;
    disY = ev.clientY - oDiv.offsetTop;
    
    document.onmousemove = fnMove;
    document.onmouseup = fnUp;
    
    return false;
}
function fnMove(ev){
    var ev = ev || window.event;
    oDiv.style.left = ev.clientX - disX + 'px';
    oDiv.style.top = ev.clientY - disY + 'px';
}
function fnUp(){
    document.onmousemove = null;
    document.onmouseup = null;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32

# 4.2 再改成面向对象

window.onload = function(){
    
    var d1 = new Drag('div1');
    d1.init();
    
};

function Drag(id){
    this.oDiv = document.getElementById(id);
    this.disX = 0;
    this.disY = 0;
}

Drag.prototype.init = function(){
    
    var This = this;
    
    this.oDiv.onmousedown = function(ev){
        var ev = ev || window.event;
        This.fnDown(ev);    
        return false;
    };
};

//ev只能在事件函数中使用,不能在function内使用
Drag.prototype.fnDown = function(ev){
    
    var This = this;
    this.disX = ev.clientX - this.oDiv.offsetLeft;
    this.disY = ev.clientY - this.oDiv.offsetTop;
    
    document.onmousemove = function(ev){
        var ev = ev || window.event;
        This.fnMove(ev);
    };
    document.onmouseup = this.fnUp;
    
};

Drag.prototype.fnMove = function(ev){
    this.oDiv.style.left = ev.clientX - this.disX + 'px';
    this.oDiv.style.top = ev.clientY - this.disY + 'px';
};
Drag.prototype.fnUp = function(){
    document.onmousemove = null;
    document.onmouseup = null;
};
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47

# 五、类

/*
    拖拽:
        1. 鼠标摁下可以开始拖拽
        2. 记录摁下时的鼠标位置 和 元素位置
        3. 移动后获取到鼠标的新位置
        4. 用鼠标新位置 - 摁下时的鼠标位置 = 鼠标移动距离
        5. 元素当前位置 = 鼠标移动距离 + 摁下时元素位置
*/    
class Drag extends Event {
    // 构造函数
    constructor(el){
        // 在构造函数中使用时,super关键字将单独出现,并且必须在使用this关键字之前使用。
        // super关键字也可以用来调用父对象上的函数。
        super();
        this.el = el;
        // 鼠标摁下时的元素的位置
        this.startOffset = {};
        // 鼠标摁下时鼠标的坐标
        this.startPoint = {};
        let move = (e)=>{
            this.move(e);
        };
        let end = (e)=>{
           document.removeEventListener("mousemove",move);
           document.removeEventListener("mouseup",end); 
           this.end(e);
        };
        el.addEventListener("mousedown",(e)=>{
           this.start(e);
           document.addEventListener("mousemove",move);
           document.addEventListener("mouseup",end);
        });
    }
    // 摁下时的处理函数
    start(e){
        let {el} = this;
        this.startOffset = {
            x: el.offsetLeft,
            y: el.offsetTop
        };
        this.startPoint = {
            x: e.clientX,
            y:e.clientY
        };
        this.trigger("dragstart",e,el);
    }
    //移动时的处理函数
    move(e){
        let {el,startOffset,startPoint} = this;
        let nowPoint = {
            x: e.clientX,
            y: e.clientY
        };
        let dis = {
            x: nowPoint.x - startPoint.x,
            y: nowPoint.y - startPoint.y
        }
        el.style.left = dis.x + startOffset.x + "px";
        el.style.top = dis.y + startOffset.y + "px";
        // 因为这里el已经赋值为this.el,就不用写成this.el了
        this.trigger("drag",e,el);
    }
    end(e){
        this.trigger("dragend",e,this.el);
    }
}
(function(){
    let box = document.querySelector("#box");
    let dragBox = new Drag(box);
    // 原生js也是有once处理
    // box.addEventListener("click",function(){
    //     alert(1);
    // },{
    //     once:true
    // })
    // console.log(dragBox);
    dragBox.on("dragstart",function(e){
        //console.log(e,this);
        //console.log("开始拖拽");
        this.style.background = "yellow";
    });
    dragBox.on("dragend",function(e){
        //console.log("结束拖拽");
        this.style.background = "red";
    });
    // 第一次执行的时候是可以遍历到这个函数并执行函数,但是在handle[type]里是被取消监听的了,随后就无法遍历到这个函数了
    dragBox.once("drag",function(){
        console.log("drag只会出现一次");
    })
})()   
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90